﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace HML.Design
{
    /// <summary>
    /// 自定义颜色控件
    /// </summary>
    [ToolboxItem(false)]
    public class AlphaColorEditorCustomColorDialog : DpiControl
    {
        #region 新增属性

        private Color colorValue = Color.Empty;
        /// <summary>
        /// 颜色
        /// </summary>
        [Browsable(false)]
        public Color ColorValue
        {
            get { return this.colorValue; }
        }

        #endregion

        #region 字段

        /// <summary>
        /// 渐变框图片
        /// </summary>
        private Bitmap gradual_bmp;
        /// <summary>
        /// 渐变框rect信息
        /// </summary>
        private Rectangle gradual_rect;
        /// <summary>
        /// 渐变框选中坐标
        /// </summary>
        private Point gradual_point = Point.Empty;

        /// <summary>
        /// 渐变栏图片
        /// </summary>
        private Bitmap gradual_bar_bmp;
        /// <summary>
        /// 渐变栏rect信息
        /// </summary>
        private Rectangle gradual_bar_rect;
        /// <summary>
        /// 渐变栏滑块rect信息
        /// </summary>
        private Rectangle gradual_bar_slide_rect;
        /// <summary>
        /// 渐变栏滑块颜色值
        /// </summary>
        private Color gradual_bar_slide_color;

        /// <summary>
        /// 当前颜色R的rect信息
        /// </summary>
        private Rectangle current_color_r_rect;
        /// <summary>
        /// 当前颜色R滑块的rect信息
        /// </summary>
        private Rectangle current_color_r_slide_rect;

        /// <summary>
        /// 当前颜色G的rect信息
        /// </summary>
        private Rectangle current_color_g_rect;
        /// <summary>
        /// 当前颜色G滑块的rect信息
        /// </summary>
        private Rectangle current_color_g_slide_rect;

        /// <summary>
        /// 当前颜色B的rect信息
        /// </summary>
        private Rectangle current_color_b_rect;
        /// <summary>
        /// 当前颜色B滑块的rect信息
        /// </summary>
        private Rectangle current_color_b_slide_rect;

        /// <summary>
        /// 当前颜色预览rect信息
        /// </summary>
        private Rectangle current_color_effect_rect;

        /// <summary>
        /// 当前鼠标状态
        /// </summary>
        private MouseDownTypes mouseDownType = MouseDownTypes.None;

        #endregion

        public AlphaColorEditorCustomColorDialog()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            this.SuspendLayout();
            this.InitializeElement();
            this.Update_GradualBar_Image();
            this.Update_GradualBarSlide_Rect(new Point(this.gradual_bar_rect.Width / 2, this.gradual_bar_rect.Height / 3));
            this.Update_Gradual_Image();
            this.Update_Gradual_Point(new Point(this.gradual_rect.Right, 0));
            this.Update_RGBSlide_Rect();
            this.ResumeLayout();

        }

        #region 重写

        protected override void OnScaleDpiChangedInitialize()
        {
            this.InitializeElement();
            this.InitializeElement();
            this.Update_GradualBar_Image();
            this.Update_GradualBarSlide_Rect(new Point(this.gradual_bar_rect.Width / 2, this.gradual_bar_rect.Height / 3));
            this.Update_Gradual_Image();
            this.Update_Gradual_Point(new Point(this.gradual_rect.Right, 0));
            this.Update_RGBSlide_Rect();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;
            Pen border_pen = new Pen(Color.FromArgb(192, 192, 192), 1);
            SolidBrush common_sb = new SolidBrush(Color.White);
            SolidBrush slide_sb = new SolidBrush(Color.FromArgb(200, 255, 255, 255));
            ImageAttributes back_image_ia = new ImageAttributes();
            back_image_ia.SetWrapMode(WrapMode.Tile);

            //背景
            common_sb.Color = this.BackColor;
            g.FillRectangle(common_sb, g.ClipBounds);

            // Gradual
            g.DrawImage(this.gradual_bmp, this.gradual_rect);
            g.DrawRectangle(border_pen, this.gradual_rect);

            Rectangle point_rect_in = new Rectangle(this.gradual_rect.X + this.gradual_point.X - 2, this.gradual_rect.Y + this.gradual_point.Y - 2, 4, 4);
            Rectangle point_rect_out = new Rectangle(this.gradual_rect.X + this.gradual_point.X - 3, this.gradual_rect.Y + this.gradual_point.Y - 3, 6, 6);
            Pen gradual_point_pen = new Pen(Color.Black, 1);
            g.DrawEllipse(gradual_point_pen, point_rect_in);
            gradual_point_pen.Color = Color.White;
            g.DrawEllipse(gradual_point_pen, point_rect_out);
            gradual_point_pen.Dispose();

            // GradualBar
            g.DrawImage(this.gradual_bar_bmp, this.gradual_bar_rect);
            g.DrawRectangle(border_pen, this.gradual_bar_rect);
            g.FillRectangle(slide_sb, this.gradual_bar_slide_rect);
            g.DrawRectangle(border_pen, this.gradual_bar_slide_rect);

            // RGB
            LinearGradientBrush argb_lgb = new LinearGradientBrush(this.current_color_r_rect, Color.Transparent, Color.Yellow, 0f);
            common_sb.Color = this.ForeColor;
            // R
            argb_lgb.LinearColors = new Color[] { Color.Transparent, Color.Red };
            g.DrawImage(HML.AlphaColorEditorResources.AlphaColorEditor_squaresback, this.current_color_r_rect, 0, 0, this.current_color_r_rect.Width, this.current_color_r_rect.Height, GraphicsUnit.Pixel, back_image_ia);
            g.FillRectangle(argb_lgb, this.current_color_r_rect);
            g.DrawRectangle(border_pen, this.current_color_r_rect);
            g.FillRectangle(slide_sb, this.current_color_r_slide_rect);
            g.DrawRectangle(border_pen, this.current_color_r_slide_rect);
            g.DrawString("R:" + this.colorValue.R.ToString().PadLeft(3, '0'), this.Font, common_sb, new Point(this.current_color_r_rect.Right + this.current_color_r_slide_rect.Width, this.current_color_r_rect.Y));

            // G
            argb_lgb.LinearColors = new Color[] { Color.Transparent, Color.Green };
            g.DrawImage(HML.AlphaColorEditorResources.AlphaColorEditor_squaresback, this.current_color_g_rect, 0, 0, this.current_color_g_rect.Width, this.current_color_g_rect.Height, GraphicsUnit.Pixel, back_image_ia);
            g.FillRectangle(argb_lgb, this.current_color_g_rect);
            g.DrawRectangle(border_pen, this.current_color_g_rect);
            g.FillRectangle(slide_sb, this.current_color_g_slide_rect);
            g.DrawRectangle(border_pen, this.current_color_g_slide_rect);
            g.DrawString("G:" + this.colorValue.G.ToString().PadLeft(3, '0'), this.Font, common_sb, new Point(this.current_color_g_rect.Right + this.current_color_g_slide_rect.Width, this.current_color_g_rect.Y));

            // B
            argb_lgb.LinearColors = new Color[] { Color.Transparent, Color.Blue };
            g.DrawImage(HML.AlphaColorEditorResources.AlphaColorEditor_squaresback, this.current_color_b_rect, 0, 0, this.current_color_b_rect.Width, this.current_color_b_rect.Height, GraphicsUnit.Pixel, back_image_ia);
            g.FillRectangle(argb_lgb, this.current_color_b_rect);
            g.DrawRectangle(border_pen, this.current_color_b_rect);
            g.FillRectangle(slide_sb, this.current_color_b_slide_rect);
            g.DrawRectangle(border_pen, this.current_color_b_slide_rect);
            g.DrawString("B:" + this.colorValue.B.ToString().PadLeft(3, '0'), this.Font, common_sb, new Point(this.current_color_b_rect.Right + this.current_color_b_slide_rect.Width, this.current_color_b_rect.Y));

            argb_lgb.Dispose();

            // 当前颜色预览
            common_sb.Color = this.colorValue;
            g.FillRectangle(common_sb, this.current_color_effect_rect);
            g.DrawRectangle(border_pen, this.current_color_effect_rect);


            border_pen.Dispose();
            common_sb.Dispose();
            slide_sb.Dispose();
            back_image_ia.Dispose();
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);

            this.mouseDownType = MouseDownTypes.None;
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            this.mouseDownType = MouseDownTypes.None;
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            if (this.gradual_rect.Contains(e.Location))
            {
                this.mouseDownType = MouseDownTypes.GradualDown;
                this.Update_Gradual_Point(e.Location);
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.gradual_bar_rect.Contains(e.Location) || this.gradual_bar_slide_rect.Contains(e.Location))
            {
                this.mouseDownType = MouseDownTypes.GradualBarDown;
                this.Update_GradualBarSlide_Rect(e.Location);
                this.Update_Gradual_Image();
                this.colorValue = this.GetGradualColor();
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.current_color_r_rect.Contains(e.Location) || this.current_color_r_slide_rect.Contains(e.Location))
            {
                this.mouseDownType = MouseDownTypes.RDown;
                this.colorValue = Color.FromArgb(this.GetRForPoint(e.Location), this.colorValue.G, this.colorValue.B);
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.current_color_g_rect.Contains(e.Location) || this.current_color_g_slide_rect.Contains(e.Location))
            {
                this.mouseDownType = MouseDownTypes.GDown;
                this.colorValue = Color.FromArgb(this.colorValue.R, this.GetGForPoint(e.Location), this.colorValue.B);
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.current_color_b_rect.Contains(e.Location) || this.current_color_b_slide_rect.Contains(e.Location))
            {
                this.mouseDownType = MouseDownTypes.BDown;
                this.colorValue = Color.FromArgb(this.colorValue.R, this.colorValue.G, this.GetBForPoint(e.Location));
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else
            {
                this.mouseDownType = MouseDownTypes.None;
            }

        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (this.mouseDownType == MouseDownTypes.GradualDown)
            {
                this.Update_Gradual_Point(e.Location);
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.mouseDownType == MouseDownTypes.GradualBarDown)
            {
                this.Update_GradualBarSlide_Rect(e.Location);
                this.Update_Gradual_Image();
                this.colorValue = this.GetGradualColor();
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.mouseDownType == MouseDownTypes.RDown)
            {
                this.colorValue = Color.FromArgb(this.GetRForPoint(e.Location), this.colorValue.G, this.colorValue.B);
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.mouseDownType == MouseDownTypes.GDown)
            {
                this.colorValue = Color.FromArgb(this.colorValue.R, this.GetGForPoint(e.Location), this.colorValue.B);
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }
            else if (this.mouseDownType == MouseDownTypes.BDown)
            {
                this.colorValue = Color.FromArgb(this.colorValue.R, this.colorValue.G, this.GetBForPoint(e.Location));
                this.Update_RGBSlide_Rect();
                this.Invalidate();
            }

        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.gradual_bmp != null)
                    this.gradual_bmp.Dispose();
                if (this.gradual_bar_bmp != null)
                    this.gradual_bar_bmp.Dispose();
            }
            base.Dispose(disposing);
        }

        #endregion

        #region 公开方法

        /// <summary>
        /// 初始化控件内部元素布局
        /// </summary>
        public void InitializeElement()
        {
            int scale_padding = (int)Math.Ceiling(5 * this.ScaleDpi);

            int scale_gradual_width = (int)Math.Ceiling(290 * this.ScaleDpi);
            int scale_gradual_height = (int)Math.Ceiling(160 * this.ScaleDpi);

            int scale_gradualbar_width = (int)Math.Ceiling(40 * this.ScaleDpi);
            int scale_gradualbar_height = (int)Math.Ceiling(220 * this.ScaleDpi);
            int scale_gradualbar_slide_height = (int)Math.Ceiling(6 * this.ScaleDpi / 2) * 2;

            int scale_argb_width = (int)Math.Ceiling(160 * this.ScaleDpi);
            int scale_argb_height = (int)Math.Ceiling(14 * this.ScaleDpi);
            int scale_argb_slide_width = (int)Math.Ceiling(8 * this.ScaleDpi / 2) * 2;

            int scale_color_chunk_width = scale_argb_height * 3 + scale_padding * 2 * 2;//预览颜色块宽度


            this.gradual_rect = new Rectangle(this.ClientRectangle.X + scale_padding, this.ClientRectangle.Y + scale_padding, scale_gradual_width, scale_gradual_height);
            this.gradual_bar_rect = new Rectangle(this.gradual_rect.Right + scale_padding * 2, this.ClientRectangle.Y + this.Padding.Top + scale_padding, scale_gradualbar_width, scale_gradualbar_height);
            this.gradual_bar_slide_rect = new Rectangle(this.gradual_bar_rect.X, this.gradual_bar_rect.Y + scale_gradualbar_slide_height / 2, this.gradual_bar_rect.Width, scale_gradualbar_slide_height);

            this.current_color_r_rect = new Rectangle(this.gradual_rect.X + scale_color_chunk_width + scale_padding * 2, this.gradual_rect.Bottom + scale_padding * 2, scale_argb_width, scale_argb_height);
            this.current_color_r_slide_rect = new Rectangle(this.current_color_r_rect.Right - scale_argb_slide_width / 2, this.current_color_r_rect.Y, scale_argb_slide_width, this.current_color_r_rect.Height);

            this.current_color_g_rect = new Rectangle(this.gradual_rect.X + scale_color_chunk_width + scale_padding * 2, this.current_color_r_rect.Bottom + scale_padding * 2, scale_argb_width, scale_argb_height);
            this.current_color_g_slide_rect = new Rectangle(this.current_color_g_rect.Right - scale_argb_slide_width / 2, this.current_color_g_rect.Y, scale_argb_slide_width, this.current_color_g_rect.Height);

            this.current_color_b_rect = new Rectangle(this.gradual_rect.X + scale_color_chunk_width + scale_padding * 2, this.current_color_g_rect.Bottom + scale_padding * 2, scale_argb_width, scale_argb_height);
            this.current_color_b_slide_rect = new Rectangle(this.current_color_b_rect.Right - scale_argb_slide_width / 2, this.current_color_b_rect.Y, scale_argb_slide_width, this.current_color_b_rect.Height);

            this.current_color_effect_rect = new Rectangle(this.gradual_rect.X, this.gradual_rect.Bottom + scale_padding * 2, scale_color_chunk_width, scale_color_chunk_width);

            this.gradual_bmp = new Bitmap(this.gradual_rect.Width, this.gradual_rect.Height);
            this.gradual_bar_bmp = new Bitmap(this.gradual_bar_rect.Width, this.gradual_bar_rect.Height);

        }

        #endregion 

        #region 私有方法

        /// <summary>
        /// 更新渐变框图片
        /// </summary>
        private void Update_Gradual_Image()
        {
            Rectangle bmp_rect = new Rectangle(0, 0, this.gradual_bmp.Width, this.gradual_bmp.Height);
            Graphics g = Graphics.FromImage(this.gradual_bmp);

            SolidBrush back_sb = new SolidBrush(this.gradual_bar_slide_color);
            g.FillRectangle(back_sb, bmp_rect);
            back_sb.Dispose();

            LinearGradientBrush gradual_h_lgb = new LinearGradientBrush(bmp_rect, Color.White, Color.Transparent, 0f);
            g.FillRectangle(gradual_h_lgb, bmp_rect);
            gradual_h_lgb.Dispose();

            LinearGradientBrush gradual_v_lgb = new LinearGradientBrush(bmp_rect, Color.Transparent, Color.Black, 90f);
            g.FillRectangle(gradual_v_lgb, bmp_rect);
            gradual_v_lgb.Dispose();

            g.Dispose();
        }

        /// <summary>
        /// 更新渐变框选中点坐标值
        /// </summary>
        /// <param name="mousePoint">鼠标坐标</param>
        private void Update_Gradual_Point(Point mousePoint)
        {
            int x = mousePoint.X - this.gradual_rect.X;
            if (x < 0)
                x = 0;
            if (x > this.gradual_rect.Width - 1)
                x = this.gradual_rect.Width - 1;
            int y = mousePoint.Y - this.gradual_rect.Y;
            if (y < 0)
                y = 0;
            if (y > this.gradual_rect.Height - 1)
                y = this.gradual_rect.Height - 1;
            this.gradual_point = new Point(x, y);

            this.colorValue = this.GetGradualColor();
        }

        /// <summary>
        /// 更新渐变栏图片
        /// </summary>
        private void Update_GradualBar_Image()
        {
            Rectangle bmp_rect = new Rectangle(0, 0, this.gradual_bar_bmp.Width, this.gradual_bar_bmp.Height);
            Graphics g = Graphics.FromImage(this.gradual_bar_bmp);
            LinearGradientBrush gradualbar_lgb = new LinearGradientBrush(this.gradual_bar_rect, Color.Transparent, Color.Transparent, 90) { InterpolationColors = new ColorBlend() { Colors = new Color[7] { Color.FromArgb(255, 0, 0), Color.FromArgb(255, 255, 0), Color.FromArgb(0, 255, 0), Color.FromArgb(0, 255, 255), Color.FromArgb(0, 0, 255), Color.FromArgb(255, 0, 255), Color.FromArgb(255, 0, 0) }, Positions = new float[7] { 0.0f, 0.17f, 0.33f, 0.50f, 0.67f, 0.83f, 1.0f } } };
            g.FillRectangle(gradualbar_lgb, bmp_rect);
            gradualbar_lgb.Dispose();
            g.Dispose();
        }

        /// <summary>
        /// 更新渐变栏滑块rect
        /// </summary>
        /// <param name="mousePoint">鼠标坐标</param>
        private void Update_GradualBarSlide_Rect(Point mousePoint)
        {
            if (mousePoint.Y < this.gradual_bar_rect.Y)
                mousePoint.Y = this.gradual_bar_rect.Y;
            if (mousePoint.Y > this.gradual_bar_rect.Bottom)
                mousePoint.Y = this.gradual_bar_rect.Bottom;

            this.gradual_bar_slide_rect.Y = mousePoint.Y - this.gradual_bar_slide_rect.Height / 2;

            this.gradual_bar_slide_color = this.GetGradualBarSlideColor();
        }

        /// <summary>
        /// 更新RGB滑块rect
        /// </summary>
        private void Update_RGBSlide_Rect()
        {
            this.current_color_r_slide_rect.X = (int)(this.current_color_r_rect.X + (this.current_color_r_rect.Width * this.colorValue.R / 255f) - this.current_color_r_slide_rect.Width / 2);
            this.current_color_g_slide_rect.X = (int)(this.current_color_g_rect.X + (this.current_color_g_rect.Width * this.colorValue.G / 255f) - this.current_color_g_slide_rect.Width / 2);
            this.current_color_b_slide_rect.X = (int)(this.current_color_b_rect.X + (this.current_color_b_rect.Width * this.colorValue.B / 255f) - this.current_color_b_slide_rect.Width / 2);
        }

        /// <summary>
        /// 获取渐变框坐标颜色
        /// </summary>
        private Color GetGradualColor()
        {
            return this.gradual_bmp.GetPixel(this.gradual_point.X, this.gradual_point.Y);
        }

        /// <summary>
        /// 获取渐变栏滑块颜色
        /// </summary>
        private Color GetGradualBarSlideColor()
        {
            int sum = this.gradual_bar_rect.Height - 1;
            int s = this.gradual_bar_slide_rect.Y + this.gradual_bar_slide_rect.Height / 2 - this.gradual_bar_rect.Y;
            if (s < 0)
                s = 0;
            if (s > sum)
                s = sum;

            return this.gradual_bar_bmp.GetPixel(this.gradual_bar_rect.Width / 2, s);
        }

        /// <summary>
        /// 获取R滑块值
        /// </summary>
        /// <param name="mousePoint">鼠标坐标</param>
        private int GetRForPoint(Point mousePoint)
        {
            int r = (int)(255 * (mousePoint.X - this.current_color_r_rect.X) / (float)this.current_color_r_rect.Width);
            if (r < byte.MinValue)
                r = byte.MinValue;
            if (r > byte.MaxValue)
                r = byte.MaxValue;
            return r;
        }

        /// <summary>
        /// 获取G滑块值
        /// </summary>
        /// <param name="mousePoint">鼠标坐标</param>
        private int GetGForPoint(Point mousePoint)
        {
            int g = (int)(255 * (mousePoint.X - this.current_color_g_rect.X) / (float)this.current_color_g_rect.Width);
            if (g < byte.MinValue)
                g = byte.MinValue;
            if (g > byte.MaxValue)
                g = byte.MaxValue;
            return g;
        }

        /// <summary>
        /// 获取B滑块值
        /// </summary>
        /// <param name="mousePoint">鼠标坐标</param>
        private int GetBForPoint(Point mousePoint)
        {
            int b = (int)(255 * (mousePoint.X - this.current_color_b_rect.X) / (float)this.current_color_b_rect.Width);
            if (b < byte.MinValue)
                b = byte.MinValue;
            if (b > byte.MaxValue)
                b = byte.MaxValue;
            return b;
        }

        #endregion

        #region 枚举

        /// <summary>
        /// 鼠标按下类型
        /// </summary>
        internal enum MouseDownTypes
        {
            /// <summary>
            /// 空
            /// </summary>
            None,
            /// <summary>
            /// 渐变框按下
            /// </summary>
            GradualDown,
            /// <summary>
            /// 渐变栏按下
            /// </summary>
            GradualBarDown,
            /// <summary>
            /// R按下
            /// </summary>
            RDown,
            /// <summary>
            /// G按下
            /// </summary>
            GDown,
            /// <summary>
            /// B按下
            /// </summary>
            BDown
        }

        #endregion
    }

}
